%{
/*
 * pascal.l
 *
 * lex input file for pascal scanner
 *
 */
#include "../src/IdentTable.hpp"
#include "../src/SymbTable.hpp"
#include "../src/type/Type.hpp"
#include "../inc/Code3ad.hpp"
#include <stdio.h>
#include <math.h>


#include "parser.hpp" 

IdentTable t;
SymbTable ts;
SymbTable tFonction;

string typeElement;
string nomElement;
string typeVar;
string retourFonction;
string nomFonction;
int fctOn = 1;
int nbArguments = 0;
int argument = 1;
int retFonction = 1;
string valRet;

extern int row, column;

extern int yyerror ( char * m );

extern int yylex();

extern void commenteof ();

extern void modifierTypeElement(string texte);
extern void ajouterTI(string texte, string type);

/*
	mot-clefs du pascal non geres pour le moment
	{C}{A}{S}{E}   return(CASE);
	{E}{X}{T}{E}{R}{N} |
	{E}{X}{T}{E}{R}{N}{A}{L} return(EXTERNAL);
	{G}{O}{T}{O}   return(GOTO);
	{I}{N}    return(IN);
	{L}{A}{B}{E}{L}   return(LABEL);
	{O}{T}{H}{E}{R}{W}{I}{S}{E} return(OTHERWISE);
	{P}{A}{C}{K}{E}{D}  return(PACKED);
	{F}{I}{L}{E}   return(PFILE);
	{S}{E}{T}   return(SET);
	{W}{I}{T}{H}   return(WITH);
	{F}{O}{R}{W}{A}{R}{D} return(FORWARD);
*/

%}

A [aA]
B [bB]
C [cC]
D [dD]
E [eE]
F [fF]
G [gG]
H [hH]
I [iI]
J [jJ]
K [kK]
L [lL]
M [mM]
N [nN]
O [oO]
P [pP]
Q [qQ]
R [rR]
S [sS]
T [tT]
U [uU]
V [vV]
W [wW]
X [xX]
Y [yY]
Z [zZ]
NQUOTE [^']
CHIFFRES [0-9]+

%%

{A}{N}{D}					column += yyleng; return KW_AND;
{A}{R}{R}{A}{Y}					column += yyleng; return KW_ARRAY;
{C}{O}{N}{S}{T}					column += yyleng; modifierTypeElement(yytext); return KW_CONST;
{D}{I}{V}					column += yyleng; return KW_DIV;
{D}{O}						column += yyleng; return KW_DO;
{D}{O}{W}{N}{T}{O}				column += yyleng; return KW_DOWNTO;
{E}{L}{S}{E}					column += yyleng; return KW_ELSE;
{E}{N}{D}					column += yyleng; {if(fctOn==0)fctOn=1;} return KW_END;
{F}{O}{R}					column += yyleng; return KW_FOR;
{F}{U}{N}{C}{T}{I}{O}{N}			column += yyleng; modifierTypeElement(yytext); return KW_FUNC;
{I}{F}						column += yyleng; return KW_IF;
{M}{O}{D}					column += yyleng; return KW_MOD;
{N}{I}{L}					column += yyleng; return KW_NIL;
{N}{O}{T}					column += yyleng; return KW_NOT;
{O}{F}						column += yyleng; return KW_OF;
{O}{R}						column += yyleng; return KW_OR;
{B}{E}{G}{I}{N}					column += yyleng; return KW_BEGIN;
{P}{R}{O}{C}{E}{D}{U}{R}{E}			column += yyleng; modifierTypeElement(yytext); return KW_PROC;
{P}{R}{O}{G}{R}{A}{M}				column += yyleng; modifierTypeElement(yytext); return KW_PROGRAM;
{R}{E}{C}{O}{R}{D}				column += yyleng; return KW_RECORD;
{R}{E}{P}{E}{A}{T}				column += yyleng; return KW_REPEAT;
{T}{H}{E}{N}					column += yyleng; return KW_THEN;
{T}{O}						column += yyleng; return KW_TO;
{T}{Y}{P}{E}					column += yyleng; return KW_TYPE;
{U}{N}{T}{I}{L}					column += yyleng; return KW_UNTIL;
{V}{A}{R}					column += yyleng; modifierTypeElement(yytext); return KW_VAR;
{W}{H}{I}{L}{E}					column += yyleng; return KW_WHILE;
{X}{O}{R}					column += yyleng; return KW_XOR;
{I}{N}{T}{E}{G}{E}{R}				column += yyleng; if (retFonction == 0) { valRet = yytext; cout << "Valeur de retour fonction : " << valRet << endl; retFonction = 1;} ; typeVar = yytext; ajouterTI(nomElement, typeElement); typeVar = ""; return KW_INTEGER;
{R}{E}{A}{L}					column += yyleng; typeVar = yytext; ajouterTI(nomElement, typeElement); typeVar = ""; return KW_REAL;
{B}{O}{O}{L}{E}{A}{N}				column += yyleng; typeVar = yytext; ajouterTI(nomElement, typeElement); typeVar = ""; return KW_BOOLEAN;
{C}{H}{A}{R}					column += yyleng; typeVar = yytext; ajouterTI(nomElement, typeElement); typeVar = ""; return KW_CHAR;
{S}{T}{R}{I}{N}{G}				column += yyleng; typeVar = yytext; ajouterTI(nomElement, typeElement); typeVar = ""; return KW_STRING;

":="						column += yyleng; return OP_AFFECT;
"="						column += yyleng; return OP_EQ;
">="						column += yyleng; return OP_GTE;
">"						column += yyleng; return OP_GT;
"<="						column += yyleng; return OP_LTE;
"<"						column += yyleng; return OP_LT;
"-"						column += yyleng; return OP_SUB;
"<>"						column += yyleng; return OP_NEQ;
"+"						column += yyleng; return OP_ADD;
"/"						column += yyleng; return OP_SLASH;
"*"						column += yyleng; return OP_MUL;
"**"						column += yyleng; return OP_EXP;
"^"						column += yyleng; return OP_PTR;

{T}{R}{U}{E}					column += yyleng; return TOK_BOOLEAN;
{F}{A}{L}{S}{E}					column += yyleng; return TOK_BOOLEAN;
[a-zA-Z]([a-zA-Z0-9])*			column += yyleng; ajouterTI(yytext, typeElement); nomElement = yytext;if(fctOn == 0){yylval.ltb.ts_c =&tFonction;	}else{		yylval.ltb.ts_c = &ts;	};yylval.ltb.id = t.getID(strdup(yytext)); return TOK_IDENT;
'({NQUOTE}|'')+'                		column += yyleng; yytext[strlen(yytext)-1] = '\0';yylval.strval = strdup(yytext+1); return TOK_STRING;
{CHIFFRES}                  			column += yyleng; yylval.intval = atoi(strdup(yytext)); return TOK_INTEGER;
{CHIFFRES}"."{CHIFFRES}         	        column += yyleng; yylval.fval = atof(strdup(yytext)); return TOK_REAL;

":"						column += yyleng; return SEP_DOTS;
";"						column += yyleng; return SEP_SCOL;
","						column += yyleng; return SEP_COMMA;
"."						column += yyleng; cout << "TABLE SYMBOLE PROGRAMME" << endl; ts.afficher(); cout << "TABLE SYMBOLE FONCTION" << endl; tFonction.afficher(); cout << "TABLE IDENTIFIANTS" << endl; t.afficher(); return SEP_DOT;
".."						column += yyleng; return SEP_DOTDOT;
"["						column += yyleng; return SEP_CO;
"]"						column += yyleng; return SEP_CF;
"("						column += yyleng; return SEP_PO;
")"						column += yyleng; if (argument == 0) { argument = 1; retFonction = 0; }return SEP_PF;

"(*"   |
"{"								{
									register int c;
									while ((c = yyinput()))
									{
										column ++;
										if (c == '}')
											break;
										else if (c == '*')
										{
											if ((c = yyinput()) == ')')
											break;
											else
											unput (c);
										}
										else if (c == '\n')
										{
											row ++;
											column = 1;
										}
										else if (c == 0)
											commenteof ();
									}
								}

[ \t\f]							column ++;

\n								row++; column = 1;

.								{
									fprintf (stderr, "'%c' (0%o): illegal charcter at line %d, column %d\n", yytext[0], yytext[0], row, column );
								}

%%

int row = 1, column = 1;


int yyerror ( char *m )
{
	fprintf ( stderr, "Erreur (%d,%d) [%s] : %s\n", row, column, yytext, m );
	return 1;
}

void commenteof ()
{
	fprintf (stderr, "unexpected EOF inside comment at line %d, column %d\n", row, column );
	exit (1);
}



void modifierTypeElement(string texte) {
	typeElement = yytext;
}


void ajouterTI(string texte, string type) {

	int id;
	
	
	// Si l'Element est une variable déclarée dans VAR, et qu'elle a un type associé (integer, boolean, etc)
	if ((typeElement.compare("VAR") == 0) && (typeVar.compare("") != 0))
	{
		argument = 1;

		cout << "Type : " << type << " nommé " << texte << " de sous type " << typeVar << endl;

		t.ajouter(texte);
		id = t.getID(texte);

		// Type variable integer
		if (typeVar.compare("integer") == 0 || typeVar.compare("INTEGER") == 0) 
		{
			if (fctOn == 0) {
				tFonction.ajouterVariable(id, Type::TYPE_INTEGER);
			}
			else{
			ts.ajouterVariable(id, Type::TYPE_INTEGER);}
		}

		// Type variable string
		if (typeVar.compare("string") == 0) 
		{
			if (fctOn == 0) {
				tFonction.ajouterVariable(id, Type::TYPE_INTEGER);
			}
			else{
			ts.ajouterVariable(id, Type::TYPE_STRING);}
		}

		// Type variable boolean
		if (typeVar.compare("boolean") == 0) 
		{
			if (fctOn == 0) {
				tFonction.ajouterVariable(id, Type::TYPE_INTEGER);
			}
			else{
			ts.ajouterVariable(id, Type::TYPE_BOOL);}
		}

		// Type variable integer
		if (typeVar.compare("real") == 0) 
		{
			if (fctOn == 0) {
				tFonction.ajouterVariable(id, Type::TYPE_REAL);
			}
			else{
			ts.ajouterVariable(id, Type::TYPE_REAL);}
		}

		// Type variable char
		if (typeVar.compare("char") == 0) 
		{
			if (fctOn == 0) {
				tFonction.ajouterVariable(id, Type::TYPE_INTEGER);
			}
			else{
			ts.ajouterVariable(id, Type::TYPE_CHAR);}
		}
	}

	// Symbole PROGRAM
	if (typeElement.compare("PROGRAM") == 0)
	{
		t.ajouter(texte);
		id = t.getID(texte);
		ts.ajouterProgram(id);
	}

	// Symbole CONST
	if (typeElement.compare("CONST") == 0)
{
	cout << "constante : " << texte << endl;
}

	// Symbole FUNCTION
	if (typeElement.compare("PROCEDURE") == 0)
	{	
		if (fctOn == 1)
		{
			t.ajouter(texte);
			id = t.getID(texte);
			fctOn = 0;
			argument = 0;
			nbArguments = 0;
			ts.ajouterProcedure(id, nbArguments, &tFonction);
			cout << "Adresse table symbole fonction : " << &tFonction << endl;

		}
	}

	// Ajout des arguments dans le cas d'une fonction
	if (typeVar != "")
	{
		if (argument == 0)
		{
			t.ajouter(texte);
			id = t.getID(texte);	
			cout << "Ajout argument " << texte << " type argument : " << typeVar << endl;

			if (typeVar.compare("char") == 0)
			{
				tFonction.ajouterArgument(id, Type::TYPE_CHAR);
				nbArguments++;
			}
			if (typeVar.compare("integer") == 0)
			{
				tFonction.ajouterArgument(id, Type::TYPE_INTEGER);
				nbArguments++;		
			}
			if (typeVar.compare("real") == 0)
			{
				tFonction.ajouterArgument(id, Type::TYPE_REAL);
				nbArguments++;
			}
			if (typeVar.compare("string") == 0)
			{
				tFonction.ajouterArgument(id, Type::TYPE_STRING);
				nbArguments++;
			}
			if (typeVar.compare("boolean") == 0)
			{
				tFonction.ajouterArgument(id, Type::TYPE_BOOL);
				nbArguments++;
				
			}

			cout << "Nombre d'arguments : " << nbArguments << endl;
		}
	}
}



